package handlers

import (
	"encoding/json"
	"net/http"
	"time"
	"log"
	"fmt"

	"github.com/gorilla/mux"
	"github.com/google/uuid"
	"github.com/robfig/cron/v3"
	
	"skedule-backend/database"
	"skedule-backend/scheduler"
	"skedule-backend/service"
	"skedule-backend/storage"
	"skedule-backend/types"
	"skedule-backend/utils"
)

// TaskHandler 任务处理器
type TaskHandler struct {
	scheduler         *scheduler.Scheduler
	executionService  *service.TaskExecutionService
}

// calculateNextRunTime 计算下次运行时间
func (h *TaskHandler) calculateNextRunTime(schedule string) time.Time {
	parser := cron.NewParser(cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow)
	if sched, err := parser.Parse(schedule); err == nil {
		return sched.Next(time.Now())
	}
	return time.Time{}
}

// convertDatabaseTaskToStorage 转换数据库任务为存储任务
func convertDatabaseTaskToStorage(dbTask *database.Task) *storage.Task {
	return &storage.Task{
		ID:          dbTask.ID,
		Name:        dbTask.Name,
		Command:     dbTask.Command,
		Schedule:    dbTask.Schedule,
		Enabled:     dbTask.Enabled,
		LastRun:     dbTask.LastRun,
		NextRun:     dbTask.NextRun,
		CreatedAt:   dbTask.CreatedAt,
		UpdatedAt:   dbTask.UpdatedAt,
		Description: dbTask.Description,
	}
}

// NewTaskHandler 创建任务处理器
func NewTaskHandler(scheduler *scheduler.Scheduler, executionService *service.TaskExecutionService) *TaskHandler {
	return &TaskHandler{
		scheduler:        scheduler,
		executionService: executionService,
	}
}

// GetTasks 获取任务列表
func (h *TaskHandler) GetTasks(w http.ResponseWriter, r *http.Request) {
	var tasks []database.Task
	if err := database.DB.Order("is_pinned DESC").Order("created_at DESC").Find(&tasks).Error; err != nil {
		Error(w, CodeDatabaseError, utils.T("tasks.list.get.failed"))
		return
	}

	// 创建响应任务列表，包含最新的运行状态和置顶状态
	var responseTasks []types.Task
	
	for _, task := range tasks {
		responseTask := types.Task{
			ID:          task.ID,
			Name:        task.Name,
			Command:     task.Command,
			Schedule:    task.Schedule,
			Enabled:     task.Enabled,
			IsPinned:    task.IsPinned,
			LastRun:     types.CustomTime{Time: task.LastRun},
			NextRun:     types.CustomTime{Time: task.NextRun},
			Description: task.Description,
			Running:     false, // 默认值
			ExecutionID: "",   // 默认值
			CreatedAt:   types.CustomTime{Time: task.CreatedAt},
			UpdatedAt:   types.CustomTime{Time: task.UpdatedAt},
		}

		// 从执行服务获取最新的运行状态
		if h.executionService != nil {
			if existingTask, exists := h.executionService.GetTask(task.ID); exists {
				responseTask.Running = existingTask.Running
				responseTask.ExecutionID = existingTask.ExecutionID
				
				// 同步运行状态到数据库（如果不一致）
				if task.Running != existingTask.Running {
					database.UpdateTaskRunningStatus(task.ID, existingTask.Running)
				}
			}
			
			// 同步任务信息到执行服务
			h.executionService.UpdateTask(&responseTask)
		}

		responseTasks = append(responseTasks, responseTask)
	}

	Success(w, responseTasks)
}

// GetTask 获取单个任务
func (h *TaskHandler) GetTask(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	taskID := vars["id"]

	var task database.Task
	if err := database.DB.First(&task, "id = ?", taskID).Error; err != nil {
		Error(w, CodeNotFound, utils.T("tasks.not.found"))
		return
	}

	Success(w, task)
}

// CreateTask 创建任务
func (h *TaskHandler) CreateTask(w http.ResponseWriter, r *http.Request) {
	var task database.Task
	if err := json.NewDecoder(r.Body).Decode(&task); err != nil {
		Error(w, CodeBadRequest, utils.T("tasks.request.invalid"))
		return
	}

	// 验证Cron表达式
	if task.Schedule == "" {
		Error(w, CodeValidationFail, utils.T("tasks.schedule.empty"))
		return
	}

	// 生成任务ID
	task.ID = uuid.New().String()
	
	// 设置时间戳
	now := time.Now()
	task.CreatedAt = now
	task.UpdatedAt = now

	// 如果任务启用，计算下次运行时间
	if task.Enabled {
		if nextRun := h.calculateNextRunTime(task.Schedule); !nextRun.IsZero() {
			task.NextRun = nextRun
		}
	}

	// 直接保存到数据库
	if err := database.DB.Create(&task).Error; err != nil {
		Error(w, CodeDatabaseError, fmt.Sprintf(utils.T("tasks.save.failed"), err.Error()))
		return
	}

	// 如果任务启用，则添加到调度器
	if task.Enabled {
		storageTask := convertDatabaseTaskToStorage(&task)
		if err := h.scheduler.ScheduleTask(storageTask); err != nil {
			// 如果调度失败，任务仍然创建成功，只是不会被调度
			log.Printf("Failed to schedule task but task created [%s]: %v", task.ID, err)
		}
	}

	// 同步任务信息到执行服务
	if h.executionService != nil {
		h.executionService.UpdateTask(&types.Task{
			ID:          task.ID,
			Name:        task.Name,
			Command:     task.Command,
			Schedule:    task.Schedule,
			Enabled:     task.Enabled,
			LastRun:     types.CustomTime{Time: task.LastRun},
			NextRun:     types.CustomTime{Time: task.NextRun},
			Description: task.Description,
			Running:     false,
			ExecutionID: "",
			CreatedAt:   types.CustomTime{Time: task.CreatedAt},
			UpdatedAt:   types.CustomTime{Time: task.UpdatedAt},
		})
	}

	SuccessWithMsg(w, utils.T("tasks.create.success"), task)
}

// UpdateTask 更新任务
func (h *TaskHandler) UpdateTask(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	taskID := vars["id"]

	var existingTask database.Task
	if err := database.DB.First(&existingTask, "id = ?", taskID).Error; err != nil {
		Error(w, CodeNotFound, utils.T("tasks.not.found"))
		return
	}

	var updateData database.Task
	if err := json.NewDecoder(r.Body).Decode(&updateData); err != nil {
		Error(w, CodeBadRequest, utils.T("tasks.request.invalid"))
		return
	}

	// 保留原有的重要字段
	updateData.ID = existingTask.ID
	updateData.CreatedAt = existingTask.CreatedAt
	updateData.UpdatedAt = time.Now()
	updateData.LastRun = existingTask.LastRun  // 保留上次执行时间
	updateData.Running = existingTask.Running  // 保留运行状态
	
	// 如果Schedule或Enabled状态发生变化，需要重新计算NextRun
	scheduleChanged := updateData.Schedule != existingTask.Schedule
	enabledChanged := updateData.Enabled != existingTask.Enabled
	
	if scheduleChanged || enabledChanged {
		if updateData.Enabled {
			// 启用状态且调度规则可能变化，重新计算NextRun
			if nextRun := h.calculateNextRunTime(updateData.Schedule); !nextRun.IsZero() {
				updateData.NextRun = nextRun
			}
		} else {
			// 禁用状态，清空NextRun
			updateData.NextRun = time.Time{}
		}
	} else {
		// 如果调度相关字段没有变化，保留原有的NextRun
		updateData.NextRun = existingTask.NextRun
	}

	// 更新数据库
	if err := database.DB.Save(&updateData).Error; err != nil {
		Error(w, CodeDatabaseError, utils.T("tasks.update.failed"))
		return
	}

	// 如果调度相关字段发生变化，更新调度器
	if scheduleChanged || enabledChanged {
		storageTask := convertDatabaseTaskToStorage(&updateData)
		if err := h.scheduler.UpdateTask(storageTask); err != nil {
			Error(w, CodeSchedulerError, fmt.Sprintf(utils.T("tasks.scheduler.update.failed"), err.Error()))
			return
		}
	}

	// 同步任务信息到执行服务
	if h.executionService != nil {
		// 保留原有的运行状态
		var running bool
		var executionID string
		if existingTask, exists := h.executionService.GetTask(taskID); exists {
			running = existingTask.Running
			executionID = existingTask.ExecutionID
		}
		
		h.executionService.UpdateTask(&types.Task{
			ID:          updateData.ID,
			Name:        updateData.Name,
			Command:     updateData.Command,
			Schedule:    updateData.Schedule,
			Enabled:     updateData.Enabled,
			LastRun:     types.CustomTime{Time: updateData.LastRun},
			NextRun:     types.CustomTime{Time: updateData.NextRun},
			Description: updateData.Description,
			Running:     running,
			ExecutionID: executionID,
			CreatedAt:   types.CustomTime{Time: updateData.CreatedAt},
			UpdatedAt:   types.CustomTime{Time: updateData.UpdatedAt},
		})
	}

	SuccessWithMsg(w, utils.T("tasks.update.success"), updateData)
}

// DeleteTask 删除任务
func (h *TaskHandler) DeleteTask(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	taskID := vars["id"]

	var task database.Task
	if err := database.DB.First(&task, "id = ?", taskID).Error; err != nil {
		Error(w, CodeNotFound, utils.T("tasks.not.found"))
		return
	}

	// 从调度器移除
	h.scheduler.RemoveTask(taskID)

	// 从执行服务中移除任务（如果正在运行，先停止）
	if h.executionService != nil {
		if existingTask, exists := h.executionService.GetTask(taskID); exists && existingTask.Running {
			// 如果任务正在运行，先停止它
			h.executionService.StopTask(taskID)
		}
		// 从执行服务中移除任务信息
		h.executionService.DeleteTask(taskID)
	}

	// 从数据库删除
	if err := database.DB.Delete(&task).Error; err != nil {
		Error(w, CodeDatabaseError, utils.T("tasks.delete.failed"))
		return
	}

	SuccessWithMsg(w, utils.T("tasks.delete.success"), nil)
}

// ToggleTask 切换任务状态
func (h *TaskHandler) ToggleTask(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	taskID := vars["id"]

	var task database.Task
	if err := database.DB.First(&task, "id = ?", taskID).Error; err != nil {
		Error(w, CodeNotFound, utils.T("tasks.not.found"))
		return
	}

	// 使用调度器的专用方法来切换任务状态
	var err error
	var statusMsg string
	if task.Enabled {
		// 当前已启用，要禁用
		err = h.scheduler.DisableTask(taskID)
		statusMsg = utils.T("tasks.disabled")
	} else {
		// 当前已禁用，要启用
		err = h.scheduler.EnableTask(taskID)
		statusMsg = utils.T("tasks.enabled")
	}

	if err != nil {
		Error(w, CodeSchedulerError, fmt.Sprintf(utils.T("tasks.toggle.failed"), err.Error()))
		return
	}

	// 重新获取任务状态（调度器方法已经更新了数据库）
	if err := database.DB.First(&task, "id = ?", taskID).Error; err != nil {
		Error(w, CodeDatabaseError, utils.T("tasks.status.get.failed"))
		return
	}

	// 同步任务信息到执行服务
	if h.executionService != nil {
		// 保留原有的运行状态
		var running bool
		var executionID string
		if existingTask, exists := h.executionService.GetTask(taskID); exists {
			running = existingTask.Running
			executionID = existingTask.ExecutionID
		}
		
		h.executionService.UpdateTask(&types.Task{
			ID:          task.ID,
			Name:        task.Name,
			Command:     task.Command,
			Schedule:    task.Schedule,
			Enabled:     task.Enabled,
			LastRun:     types.CustomTime{Time: task.LastRun},
			NextRun:     types.CustomTime{Time: task.NextRun},
			Description: task.Description,
			Running:     running,
			ExecutionID: executionID,
			CreatedAt:   types.CustomTime{Time: task.CreatedAt},
			UpdatedAt:   types.CustomTime{Time: task.UpdatedAt},
		})
	}

	SuccessWithMsg(w, statusMsg, task)
}

// StopTask 停止任务
func (h *TaskHandler) StopTask(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	taskID := vars["id"]

	// 检查任务是否存在
	var task database.Task
	if err := database.DB.First(&task, "id = ?", taskID).Error; err != nil {
		Error(w, CodeNotFound, utils.T("tasks.not.found"))
		return
	}

	// 停止任务执行
	if h.executionService != nil {
		response, err := h.executionService.StopTask(taskID)
		if err != nil {
			Error(w, CodeInternalError, fmt.Sprintf(utils.T("tasks.stop.failed"), err.Error()))
			return
		}

		// 如果停止成功，同步运行状态到数据库
		if response.Success {
			database.UpdateTaskRunningStatus(taskID, false)
		}

		Success(w, response)
		return
	}

	// 如果没有执行服务，返回成功（向后兼容）
	SuccessWithMsg(w, utils.T("tasks.stop.request.sent"), map[string]interface{}{
		"success": true,
		"message": utils.T("tasks.stop.request.sent"),
	})
}

// ExecuteTask 执行任务
func (h *TaskHandler) ExecuteTask(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	taskID := vars["id"]

	// 检查任务是否存在
	var task database.Task
	if err := database.DB.First(&task, "id = ?", taskID).Error; err != nil {
		Error(w, CodeNotFound, utils.T("tasks.not.found"))
		return
	}

	// 执行任务
	if h.executionService != nil {
		// 先从执行服务获取最新的运行状态
		var currentlyRunning bool
		var currentExecutionID string
		if existingTask, exists := h.executionService.GetTask(taskID); exists {
			currentlyRunning = existingTask.Running
			currentExecutionID = existingTask.ExecutionID
		}
		
		// 如果任务正在运行，返回错误信息（包含executionId）
		if currentlyRunning {
			Error(w, CodeInternalError, fmt.Sprintf(utils.T("handler.task.running"), currentExecutionID))
			return
		}
		
		// 将任务信息同步到执行服务中
		h.executionService.UpdateTask(&types.Task{
			ID:          task.ID,
			Name:        task.Name,
			Command:     task.Command,
			Schedule:    task.Schedule,
			Enabled:     task.Enabled,
			LastRun:     types.CustomTime{Time: task.LastRun},
			NextRun:     types.CustomTime{Time: task.NextRun},
			Description: task.Description,
			Running:     currentlyRunning,
			ExecutionID: currentExecutionID,
			CreatedAt:   types.CustomTime{Time: task.CreatedAt},
			UpdatedAt:   types.CustomTime{Time: task.UpdatedAt},
		})
		
		response, err := h.executionService.ExecuteTask(taskID)
		if err != nil {
			Error(w, CodeInternalError, fmt.Sprintf(utils.T("tasks.execute.failed"), err.Error()))
			return
		}

		// 如果执行成功，同步运行状态到数据库
		if response.Success {
			database.UpdateTaskRunningStatus(taskID, true)
		}

		SuccessWithMsg(w, utils.T("tasks.execute.success"), response)
		return
	}

	// 如果没有执行服务，返回成功（向后兼容）
	SuccessWithMsg(w, utils.T("tasks.execute.request.sent"), map[string]interface{}{
		"success":     true,
		"executionId": "mock-execution-id",
		"message":     utils.T("tasks.execute.request.sent"),
	})
}

// GetExecution 获取执行记录
func (h *TaskHandler) GetExecution(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	executionID := vars["id"]

	// 获取执行记录
	if h.executionService != nil {
		response, err := h.executionService.GetExecution(executionID)
		if err != nil {
			Error(w, CodeNotFound, fmt.Sprintf(utils.T("tasks.execution.get.failed"), err.Error()))
			return
		}

		// 直接返回 TaskExecution 数据，而不是包装的 ExecutionResponse
		Success(w, response.Data)
		return
	}

	// 如果没有执行服务，返回空数据（向后兼容）
	Error(w, CodeInternalError, utils.T("tasks.execution.service.unavailable"))
}

// TogglePinTask 切换任务置顶状态
func (h *TaskHandler) TogglePinTask(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	taskID := vars["id"]

	var task database.Task
	if err := database.DB.First(&task, "id = ?", taskID).Error; err != nil {
		Error(w, CodeNotFound, utils.T("tasks.not.found"))
		return
	}

	// 切换置顶状态
	task.IsPinned = !task.IsPinned
	task.UpdatedAt = time.Now()

	if err := database.DB.Save(&task).Error; err != nil {
		Error(w, CodeDatabaseError, utils.T("tasks.pin.update.failed"))
		return
	}

	// 同步任务信息到执行服务（如果需要，虽然置顶状态主要影响列表排序）
	if h.executionService != nil {
		// 注意：需要将 database.Task 转换为 types.Task，并考虑 IsPinned 字段
		typesTask := types.Task{
			ID:          task.ID,
			Name:        task.Name,
			Command:     task.Command,
			Schedule:    task.Schedule,
			Enabled:     task.Enabled,
			IsPinned:    task.IsPinned, // 确保 types.Task 也有此字段
			LastRun:     types.CustomTime{Time: task.LastRun},
			NextRun:     types.CustomTime{Time: task.NextRun},
			Description: task.Description,
			CreatedAt:   types.CustomTime{Time: task.CreatedAt},
			UpdatedAt:   types.CustomTime{Time: task.UpdatedAt},
		}
		// 如果 executionService 内部缓存的任务有关联的运行状态，需要一并传入
		if esTask, exists := h.executionService.GetTask(task.ID); exists {
			typesTask.Running = esTask.Running
			typesTask.ExecutionID = esTask.ExecutionID
		}
		h.executionService.UpdateTask(&typesTask)
	}

	msg := utils.T("tasks.pin.unpinned")
	if task.IsPinned {
		msg = utils.T("tasks.pin.pinned")
	}
	SuccessWithMsg(w, msg, task) // 返回更新后的任务
}

// SetupTaskRoutes 设置任务路由
func SetupTaskRoutes(router *mux.Router, taskHandler *TaskHandler) {
	taskRouter := router.PathPrefix("/tasks").Subrouter()
	taskRouter.HandleFunc("", taskHandler.GetTasks).Methods("GET")
	taskRouter.HandleFunc("", taskHandler.CreateTask).Methods("POST")
	taskRouter.HandleFunc("/{id}", taskHandler.GetTask).Methods("GET")
	taskRouter.HandleFunc("/{id}", taskHandler.UpdateTask).Methods("PUT")
	taskRouter.HandleFunc("/{id}", taskHandler.DeleteTask).Methods("DELETE")
	taskRouter.HandleFunc("/{id}/toggle", taskHandler.ToggleTask).Methods("POST")
	taskRouter.HandleFunc("/{id}/toggle-pin", taskHandler.TogglePinTask).Methods("POST")
	taskRouter.HandleFunc("/{id}/execute", taskHandler.ExecuteTask).Methods("POST")
	taskRouter.HandleFunc("/{id}/stop", taskHandler.StopTask).Methods("POST")
	taskRouter.HandleFunc("/executions/{id}", taskHandler.GetExecution).Methods("GET")
} 